const dgram = require('dgram');
const WebSocket = require('ws');
const { Worker, isMainThread, parentPort } = require('worker_threads');
//https://support.forzamotorsport.net/hc/en-us/articles/21742934024211-Forza-Motorsport-Data-Out-Documentation
const configs = {

	"Dash": [
		{
			"name": "IsRaceOn",
			"type": "S32",
			"offset": 0,
			"bytes": 4,
			"description": "= 1 when race is on. = 0 when in menus/race stopped."
		},
		{
			"name": "TimestampMS",
			"type": "U32",
			"offset": 4,
			"bytes": 4,
			"description": "Can overflow to 0 eventually."
		},
		{
			"name": "EngineMaxRpm",
			"type": "F32",
			"offset": 8,
			"bytes": 4,
			"description": "Maximum RPM of the engine."
		},
		{
			"name": "EngineIdleRpm",
			"type": "F32",
			"offset": 12,
			"bytes": 4,
			"description": "Idle RPM of the engine."
		},
		{
			"name": "CurrentEngineRpm",
			"type": "F32",
			"offset": 16,
			"bytes": 4,
			"description": "Current RPM of the engine."
		},
		{
			"name": "AccelerationX",
			"type": "F32",
			"offset": 20,
			"bytes": 4,
			"description": "Acceleration in the car's local space (X = right)."
		},
		{
			"name": "AccelerationY",
			"type": "F32",
			"offset": 24,
			"bytes": 4,
			"description": "Acceleration in the car's local space (Y = up)."
		},
		{
			"name": "AccelerationZ",
			"type": "F32",
			"offset": 28,
			"bytes": 4,
			"description": "Acceleration in the car's local space (Z = forward)."
		},
		{
			"name": "VelocityX",
			"type": "F32",
			"offset": 32,
			"bytes": 4,
			"description": "Velocity in the car's local space (X = right)."
		},
		{
			"name": "VelocityY",
			"type": "F32",
			"offset": 36,
			"bytes": 4,
			"description": "Velocity in the car's local space (Y = up)."
		},
		{
			"name": "VelocityZ",
			"type": "F32",
			"offset": 40,
			"bytes": 4,
			"description": "Velocity in the car's local space (Z = forward)."
		},
		{
			"name": "AngularVelocityX",
			"type": "F32",
			"offset": 44,
			"bytes": 4,
			"description": "Angular velocity in the car's local space (X = pitch)."
		},
		{
			"name": "AngularVelocityY",
			"type": "F32",
			"offset": 48,
			"bytes": 4,
			"description": "Angular velocity in the car's local space (Y = yaw)."
		},
		{
			"name": "AngularVelocityZ",
			"type": "F32",
			"offset": 52,
			"bytes": 4,
			"description": "Angular velocity in the car's local space (Z = roll)."
		},
		{
			"name": "Yaw",
			"type": "F32",
			"offset": 56,
			"bytes": 4,
			"description": "Yaw angle of the car."
		},
		{
			"name": "Pitch",
			"type": "F32",
			"offset": 60,
			"bytes": 4,
			"description": "Pitch angle of the car."
		},
		{
			"name": "Roll",
			"type": "F32",
			"offset": 64,
			"bytes": 4,
			"description": "Roll angle of the car."
		},
		{
			"name": "NormalizedSuspensionTravelFrontLeft",
			"type": "F32",
			"offset": 68,
			"bytes": 4,
			"description": "Normalized suspension travel (0.0 = max stretch, 1.0 = max compression) for front left wheel."
		},
		{
			"name": "NormalizedSuspensionTravelFrontRight",
			"type": "F32",
			"offset": 72,
			"bytes": 4,
			"description": "Normalized suspension travel (0.0 = max stretch, 1.0 = max compression) for front right wheel."
		},
		{
			"name": "NormalizedSuspensionTravelRearLeft",
			"type": "F32",
			"offset": 76,
			"bytes": 4,
			"description": "Normalized suspension travel (0.0 = max stretch, 1.0 = max compression) for rear left wheel."
		},
		{
			"name": "NormalizedSuspensionTravelRearRight",
			"type": "F32",
			"offset": 80,
			"bytes": 4,
			"description": "Normalized suspension travel (0.0 = max stretch, 1.0 = max compression) for rear right wheel."
		},
		{
			"name": "TireSlipRatioFrontLeft",
			"type": "F32",
			"offset": 84,
			"bytes": 4,
			"description": "Normalized tire slip ratio (0 = 100% grip, |ratio| > 1.0 = loss of grip) for front left tire."
		},
		{
			"name": "TireSlipRatioFrontRight",
			"type": "F32",
			"offset": 88,
			"bytes": 4,
			"description": "Normalized tire slip ratio (0 = 100% grip, |ratio| > 1.0 = loss of grip) for front right tire."
		},
		{
			"name": "TireSlipRatioRearLeft",
			"type": "F32",
			"offset": 92,
			"bytes": 4,
			"description": "Normalized tire slip ratio (0 = 100% grip, |ratio| > 1.0 = loss of grip) for rear left tire."
		},
		{
			"name": "TireSlipRatioRearRight",
			"type": "F32",
			"offset": 96,
			"bytes": 4,
			"description": "Normalized tire slip ratio (0 = 100% grip, |ratio| > 1.0 = loss of grip) for rear right tire."
		},
		{
			"name": "WheelRotationSpeedFrontLeft",
			"type": "F32",
			"offset": 100,
			"bytes": 4,
			"description": "Wheel rotation speed in radians/sec for front left wheel."
		},
		{
			"name": "WheelRotationSpeedFrontRight",
			"type": "F32",
			"offset": 104,
			"bytes": 4,
			"description": "Wheel rotation speed in radians/sec for front right wheel."
		},
		{
			"name": "WheelRotationSpeedRearLeft",
			"type": "F32",
			"offset": 108,
			"bytes": 4,
			"description": "Wheel rotation speed in radians/sec for rear left wheel."
		},
		{
			"name": "WheelRotationSpeedRearRight",
			"type": "F32",
			"offset": 112,
			"bytes": 4,
			"description": "Wheel rotation speed in radians/sec for rear right wheel."
		},
		{
			"name": "WheelOnRumbleStripFrontLeft",
			"type": "S32",
			"offset": 116,
			"bytes": 4,
			"description": "= 1 when wheel is on rumble strip, = 0 when off (front left wheel)."
		},
		{
			"name": "WheelOnRumbleStripFrontRight",
			"type": "S32",
			"offset": 120,
			"bytes": 4,
			"description": "= 1 when wheel is on rumble strip, = 0 when off (front right wheel)."
		},
		{
			"name": "WheelOnRumbleStripRearLeft",
			"type": "S32",
			"offset": 124,
			"bytes": 4,
			"description": "= 1 when wheel is on rumble strip, = 0 when off (rear left wheel)."
		},
		{
			"name": "WheelOnRumbleStripRearRight",
			"type": "S32",
			"offset": 128,
			"bytes": 4,
			"description": "= 1 when wheel is on rumble strip, = 0 when off (rear right wheel)."
		},
		{
			"name": "WheelInPuddleDepthFrontLeft",
			"type": "F32",
			"offset": 132,
			"bytes": 4,
			"description": "= from 0 to 1, where 1 is the deepest puddle (front left wheel)."
		},
		{
			"name": "WheelInPuddleDepthFrontRight",
			"type": "F32",
			"offset": 136,
			"bytes": 4,
			"description": "= from 0 to 1, where 1 is the deepest puddle (front right wheel)."
		},
		{
			"name": "WheelInPuddleDepthRearLeft",
			"type": "F32",
			"offset": 140,
			"bytes": 4,
			"description": "= from 0 to 1, where 1 is the deepest puddle (rear left wheel)."
		},
		{
			"name": "WheelInPuddleDepthRearRight",
			"type": "F32",
			"offset": 144,
			"bytes": 4,
			"description": "= from 0 to 1, where 1 is the deepest puddle (rear right wheel)."
		},
		{
			"name": "SurfaceRumbleFrontLeft",
			"type": "F32",
			"offset": 148,
			"bytes": 4,
			"description": "Non-dimensional surface rumble values passed to controller force feedback (front left wheel)."
		},
		{
			"name": "SurfaceRumbleFrontRight",
			"type": "F32",
			"offset": 152,
			"bytes": 4,
			"description": "Non-dimensional surface rumble values passed to controller force feedback (front right wheel)."
		},
		{
			"name": "SurfaceRumbleRearLeft",
			"type": "F32",
			"offset": 156,
			"bytes": 4,
			"description": "Non-dimensional surface rumble values passed to controller force feedback (rear left wheel)."
		},
		{
			"name": "SurfaceRumbleRearRight",
			"type": "F32",
			"offset": 160,
			"bytes": 4,
			"description": "Non-dimensional surface rumble values passed to controller force feedback (rear right wheel)."
		},
		{
			"name": "TireSlipAngleFrontLeft",
			"type": "F32",
			"offset": 164,
			"bytes": 4,
			"description": "Normalized tire slip angle (0 = 100% grip, |angle| > 1.0 = loss of grip) for front left tire."
		},
		{
			"name": "TireSlipAngleFrontRight",
			"type": "F32",
			"offset": 168,
			"bytes": 4,
			"description": "Normalized tire slip angle (0 = 100% grip, |angle| > 1.0 = loss of grip) for front right tire."
		},
		{
			"name": "TireSlipAngleRearLeft",
			"type": "F32",
			"offset": 172,
			"bytes": 4,
			"description": "Normalized tire slip angle (0 = 100% grip, |angle| > 1.0 = loss of grip) for rear left tire."
		},
		{
			"name": "TireSlipAngleRearRight",
			"type": "F32",
			"offset": 176,
			"bytes": 4,
			"description": "Normalized tire slip angle (0 = 100% grip, |angle| > 1.0 = loss of grip) for rear right tire."
		},
		{
			"name": "TireCombinedSlipFrontLeft",
			"type": "F32",
			"offset": 180,
			"bytes": 4,
			"description": "Normalized tire combined slip (0 = 100% grip, |slip| > 1.0 = loss of grip) for front left tire."
		},
		{
			"name": "TireCombinedSlipFrontRight",
			"type": "F32",
			"offset": 184,
			"bytes": 4,
			"description": "Normalized tire combined slip (0 = 100% grip, |slip| > 1.0 = loss of grip) for front right tire."
		},
		{
			"name": "TireCombinedSlipRearLeft",
			"type": "F32",
			"offset": 188,
			"bytes": 4,
			"description": "Normalized tire combined slip (0 = 100% grip, |slip| > 1.0 = loss of grip) for rear left tire."
		},
		{
			"name": "TireCombinedSlipRearRight",
			"type": "F32",
			"offset": 192,
			"bytes": 4,
			"description": "Normalized tire combined slip (0 = 100% grip, |slip| > 1.0 = loss of grip) for rear right tire."
		},
		{
			"name": "SuspensionTravelMetersFrontLeft",
			"type": "F32",
			"offset": 196,
			"bytes": 4,
			"description": "Actual suspension travel in meters for front left wheel."
		},
		{
			"name": "SuspensionTravelMetersFrontRight",
			"type": "F32",
			"offset": 200,
			"bytes": 4,
			"description": "Actual suspension travel in meters for front right wheel."
		},
		{
			"name": "SuspensionTravelMetersRearLeft",
			"type": "F32",
			"offset": 204,
			"bytes": 4,
			"description": "Actual suspension travel in meters for rear left wheel."
		},
		{
			"name": "SuspensionTravelMetersRearRight",
			"type": "F32",
			"offset": 208,
			"bytes": 4,
			"description": "Actual suspension travel in meters for rear right wheel."
		},
		{
			"name": "CarOrdinal",
			"type": "S32",
			"offset": 212,
			"bytes": 4,
			"description": "Unique ID of the car make/model."
		},
		{
			"name": "CarClass",
			"type": "S32",
			"offset": 216,
			"bytes": 4,
			"description": "Between 0 (D -- worst cars) and 7 (X class -- best cars) inclusive."
		},
		{
			"name": "CarPerformanceIndex",
			"type": "S32",
			"offset": 220,
			"bytes": 4,
			"description": "Between 100 (worst car) and 999 (best car) inclusive."
		},
		{
			"name": "DrivetrainType",
			"type": "S32",
			"offset": 224,
			"bytes": 4,
			"description": "0 = FWD, 1 = RWD, 2 = AWD."
		},
		{
			"name": "NumCylinders",
			"type": "S32",
			"offset": 228,
			"bytes": 4,
			"description": "Number of cylinders in the engine."
		},
		{
			"name": "PositionX",
			"type": "F32",
			"offset": 232,
			"bytes": 4,
			"description": "X coordinate of the car's position."
		},
		{
			"name": "PositionY",
			"type": "F32",
			"offset": 236,
			"bytes": 4,
			"description": "Y coordinate of the car's position."
		},
		{
			"name": "PositionZ",
			"type": "F32",
			"offset": 240,
			"bytes": 4,
			"description": "Z coordinate of the car's position."
		},
		{
			"name": "Speed",
			"type": "F32",
			"offset": 244,
			"bytes": 4,
			"description": "Current speed of the car."
		},
		{
			"name": "Power",
			"type": "F32",
			"offset": 248,
			"bytes": 4,
			"description": "Current power output of the engine."
		},
		{
			"name": "Torque",
			"type": "F32",
			"offset": 252,
			"bytes": 4,
			"description": "Current torque output of the engine."
		},
		{
			"name": "TireTempFrontLeft",
			"type": "F32",
			"offset": 256,
			"bytes": 4,
			"description": "Temperature of the front left tire."
		},
		{
			"name": "TireTempFrontRight",
			"type": "F32",
			"offset": 260,
			"bytes": 4,
			"description": "Temperature of the front right tire."
		},
		{
			"name": "TireTempRearLeft",
			"type": "F32",
			"offset": 264,
			"bytes": 4,
			"description": "Temperature of the rear left tire."
		},
		{
			"name": "TireTempRearRight",
			"type": "F32",
			"offset": 268,
			"bytes": 4,
			"description": "Temperature of the rear right tire."
		},
		{
			"name": "Boost",
			"type": "F32",
			"offset": 272,
			"bytes": 4,
			"description": "Current boost level."
		},
		{
			"name": "Fuel",
			"type": "F32",
			"offset": 276,
			"bytes": 4,
			"description": "Remaining fuel in the car."
		},
		{
			"name": "DistanceTraveled",
			"type": "F32",
			"offset": 280,
			"bytes": 4,
			"description": "Total distance traveled by the car."
		},
		{
			"name": "BestLap",
			"type": "F32",
			"offset": 284,
			"bytes": 4,
			"description": "Best lap time of the car."
		},
		{
			"name": "LastLap",
			"type": "F32",
			"offset": 288,
			"bytes": 4,
			"description": "Time of the last completed lap."
		},
		{
			"name": "CurrentLap",
			"type": "F32",
			"offset": 292,
			"bytes": 4,
			"description": "Time of the current lap."
		},
		{
			"name": "CurrentRaceTime",
			"type": "F32",
			"offset": 296,
			"bytes": 4,
			"description": "Total race time elapsed."
		},
		{
			"name": "LapNumber",
			"type": "U16",
			"offset": 300,
			"bytes": 2,
			"description": "Current lap number."
		},
		{
			"name": "RacePosition",
			"type": "U8",
			"offset": 302,
			"bytes": 1,
			"description": "Current race position of the car."
		},
		{
			"name": "Accel",
			"type": "U8",
			"offset": 303,
			"bytes": 1,
			"description": "Current acceleration input."
		},
		{
			"name": "Brake",
			"type": "U8",
			"offset": 304,
			"bytes": 1,
			"description": "Current brake input."
		},
		{
			"name": "Clutch",
			"type": "U8",
			"offset": 305,
			"bytes": 1,
			"description": "Current clutch input."
		},
		{
			"name": "HandBrake",
			"type": "U8",
			"offset": 306,
			"bytes": 1,
			"description": "Current handbrake input."
		},
		{
			"name": "Gear",
			"type": "U8",
			"offset": 307,
			"bytes": 1,
			"description": "Current gear selected."
		},
		{
			"name": "Steer",
			"type": "S8",
			"offset": 308,
			"bytes": 1,
			"description": "Current steering input."
		},
		{
			"name": "NormalizedDrivingLine",
			"type": "S8",
			"offset": 309,
			"bytes": 1,
			"description": "Normalized driving line input."
		},
		{
			"name": "NormalizedAIBrakeDifference",
			"type": "S8",
			"offset": 310,
			"bytes": 1,
			"description": "Normalized AI brake difference."
		},
		{
			"name": "TireWearFrontLeft",
			"type": "F32",
			"offset": 311,
			"bytes": 4,
			"description": "Wear level of the front left tire."
		},
		{
			"name": "TireWearFrontRight",
			"type": "F32",
			"offset": 315,
			"bytes": 4,
			"description": "Wear level of the front right tire."
		},
		{
			"name": "TireWearRearLeft",
			"type": "F32",
			"offset": 319,
			"bytes": 4,
			"description": "Wear level of the rear left tire."
		},
		{
			"name": "TireWearRearRight",
			"type": "F32",
			"offset": 323,
			"bytes": 4,
			"description": "Wear level of the rear right tire."
		},
		{
			"name": "TrackOrdinal",
			"type": "S32",
			"offset": 327,
			"bytes": 4,
			"description": "Unique ID for the track."
		}
	]
};

const config = configs.Dash; //当前数据配置

if (isMainThread) {
	// 主线程：启动UDP服务器
	const udpServer = dgram.createSocket('udp4');
	const wss = new WebSocket.Server({ port: 8080 });
	console.log('WebSocket server started on port 8080');
	// 启动WebSocket转发线程
	const worker = new Worker(__filename);
	worker.on('message', (data) => {
		wss.clients.forEach(client => {
			if (client.readyState === WebSocket.OPEN) {
				client.send(data);
			}
		});
	});

	udpServer.on('message', (message) => {
		const buffer = Buffer.from(message);
		//根据config配置解析数据
		const data = {};
		for (let i = 0; i < config.length; i++) {
			const item = config[i];
			/**
			 * Type notes:
			[Letter][Number]
			The letter defines the type from one of the following:
			S Signed Integer
			U Unsigned Integer
			F Floating Point
			The number defines the amount of bits used.
			Examples:
			S8 is a signed byte with potential values between -128 and 127.
			F32 is a 32-bit floating point number, equivalent to float/single
			 */
			if (item.type === 'F32') { // 浮点数
				data[item.name] = buffer.readFloatLE(item.offset);
			} else if (item.type === 'S32') { // 整型
				data[item.name] = buffer.readInt32LE(item.offset);
			} else if (item.type === 'U16') { // 短整型
				data[item.name] = buffer.readUInt16LE(item.offset);
			} else if (item.type === 'U8') { // 字节型
				data[item.name] = buffer.readUInt8(item.offset);
			} else if (item.type === 'S8') { // 字节型
				data[item.name] = buffer.readInt8(item.offset);
			}
		}
		worker.postMessage(JSON.stringify(data)); // 将数据发送到子线程
	});

	udpServer.bind(41234); // 绑定UDP端口
	console.log('UDP server started on port 41234');



	//创建一个http服务，展示./目录下所有文件
	const http = require('http');
	const fs = require('fs');
	const path = require('path');
	const url = require('url');
	const os = require('os');

	const PORT = 8081;
	const DEFAULT_FILE = 'index.html';
	const MIME_TYPES = {
		'.html': 'text/html',
		'.js': 'text/javascript',
		'.css': 'text/css',
		'.png': 'image/png',
		'.jpg': 'image/jpeg',
		'.json': 'application/json',
		'.ini' : 'text/plain',
	};

	const server = http.createServer(async (req, res) => {
		try {
			const parsedUrl = url.parse(req.url);
			let pathname = path.join(process.cwd(),'public/', parsedUrl.pathname);

			//save请求处理
			if (req.method === 'POST' && parsedUrl.pathname === '/save') {
				const body = [];
				req.on('data', (chunk) => {
					body.push(chunk);
				}).on('end', () => {
					const buffer = Buffer.concat(body);
					const filename = path.join(process.cwd(), 'public/rpmZone.ini');
					fs.writeFile(filename, buffer, (err) => {
						if (err) {
							console.error('Save error:', err);
							res.statusCode = 500;
							res.end('Internal Server Error');
						} else {
							res.statusCode = 200;
							res.end('Save success');
						}
					});
				});
				return;
			}

			// 处理默认文件
			if (pathname.endsWith('/')) {
				pathname = path.join(pathname, DEFAULT_FILE);
			}

			// 安全验证：防止目录遍历
			if (!pathname.startsWith(process.cwd())) {
				res.statusCode = 403;
				return res.end('Forbidden');
			}

			// 获取文件状态
			const stats = await fs.promises.stat(pathname).catch(() => null);

			if (!stats) {
				res.statusCode = 404;
				return res.end('File not found');
			}

			if (stats.isDirectory()) {
				res.statusCode = 301;
				res.setHeader('Location', parsedUrl.pathname + '/');
				return res.end();
			}

			// 设置MIME类型
			const ext = path.extname(pathname);
			const contentType = MIME_TYPES[ext] || 'text/plain';
			res.setHeader('Content-Type', contentType);
			res.setHeader('Content-Length', stats.size);
			res.setHeader('Content-Encoding', 'utf-8');

			// 流式读取文件
			const stream = fs.createReadStream(pathname);
			stream.on('error', (err) => {
				console.error('File read error:', err);
				if (!res.headersSent) {
					res.statusCode = 500;
					res.end('Internal Server Error');
				}
			});

			stream.pipe(res);

		} catch (err) {
			console.error('Server error:', err);
			if (!res.headersSent) {
				res.statusCode = 500;
				res.end('Internal Server Error');
			}
		}
	});

	const getLocalIP = () => {
		const interfaces = os.networkInterfaces();
		for (const interfaceName in interfaces) {
		  const addresses = interfaces[interfaceName];
		  for (const address of addresses) {
			// 过滤掉非 IPv4 地址和回环地址
			if (address.family === 'IPv4' && !address.internal) {
			  return address.address;
			}
		  }
		}
		return null; // 如果没有找到局域网 IP，返回 null
	  }

	server.listen(PORT, () => {
		console.log(`访问地址： http://${getLocalIP()}:${PORT}/`);
	});
} else {
	// 子线程：处理数据转发
	parentPort.on('message', (data) => {
		// 这里可以添加数据处理逻辑
		parentPort.postMessage(data); // 将数据转发回主线程
	});
}